﻿
Imports System.Text
Imports std

Namespace internalFunctions

    'parameters, s, input string
    'output, int, length of string
    Public Class _strlen
        Inherits internalFunction

        Public Class parameters
            Public Const s As String = "s"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.s)
        End Sub

        Public Sub New()
            MyBase.New("strlen", m)
        End Sub

        Private Shared Function matchtype(ByVal v As bare_variable) As Boolean
            Return Not v Is Nothing AndAlso _
                   (v.variable().type() = typeDefination.string OrElse v.variable().type() = typeDefination.var)
        End Function

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim s As bare_variable = Nothing
            s = ctx.findVariable(parameters.s)
            If s Is Nothing OrElse Not matchtype(s) Then
                raiseError("expect string type parameter " + parameters.s, errorHandle.errorType.user)
                Return False
            Else
                output = New bare_variable(typeDefination.int, Global.strlen(Convert.ToString(s.value())))
                Return True
            End If
        End Function
    End Class

    'parameters, s1, input string, any, convert to string
    '            s2, input string, any, convert to string
    '            ...
    '            sn, input string, any, convert to string
    'output, string, new string = s1+s2
    Public Class _strcat
        Inherits internalFunction

        Public Class parameters
            Public Const sbase As String = "s"
        End Class

        Private Shared a As aliases = Nothing
        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialSerialMapping(m, parameters.sbase)
            initialAliases(a, "s+")
        End Sub

        Public Sub New()
            MyBase.New("strcat", m, a)
        End Sub

        Private Shared Function callback(ByVal name As String, ByVal v As String, ByRef obj As Object) As Boolean
            convertor.cast(Of StringBuilder)(obj).Append(v)
            Return True
        End Function

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim rtn As StringBuilder = Nothing
            rtn = New StringBuilder()
            If Not ctx.findVariables(AddressOf callback, string_finder, parameters.sbase, 0, rtn) Then
                'match old version of scripts
                ctx.findVariables(AddressOf callback, string_finder, parameters.sbase, 1, rtn)
            End If

            output = New bare_variable(typeDefination.string, Convert.ToString(rtn))
            free(rtn)
            Return True
        End Function
    End Class

    'parameters, s1, input string, any, convert to string
    '            s2, input string, any, convert to string
    '            carecase, any, treat as bool, optional, whether care case when compare
    'return, int, the result of strcmp(s1,s2)
    Public Class _strcmp
        Inherits internalFunction

        Public Class parameters
            Public Const s1 As String = "s1"
            Public Const s2 As String = "s2"
            Public Const carecase As String = "carecase"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.s1, parameters.s2, parameters.carecase)
        End Sub

        Public Sub New()
            MyBase.New("strcmp", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim s1 As String = Nothing
            If ctx.findVariableStr(parameters.s1, s1) Then
                Dim s2 As String = Nothing
                If ctx.findVariableStr(parameters.s2, s2) Then
                    Dim carecase As bare_variable = Nothing
                    Dim rtn As Int64
                    If ctx.findVariable(parameters.carecase, carecase) Then
                        rtn = Global.strcmp(s1, s2, carecase.true())
                    Else
                        rtn = Global.strcmp(s1, s2)
                    End If
                    output = New bare_variable(typeDefination.int, rtn)
                    Return True
                Else
                    raiseError("expect parameter " + parameters.s2, errorHandle.errorType.user)
                    Return False
                End If
            Else
                raiseError("expect parameter " + parameters.s1, errorHandle.errorType.user)
                Return False
            End If
        End Function
    End Class

    'parameters, s, any, convert to string, input string
    '            index, int / var, the start index, 0-based
    '            len, optional, int / var, the length required, default value is npos, same behavior as strmid
    'return, string, the sub string [from] index to index+len, or index to the end
    Public Class _strmid
        Inherits internalFunction

        Public Class parameters
            Public Const s As String = "s"
            Public Const index As String = "index"
            Public Const len As String = "len"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.s, parameters.index, parameters.len)
        End Sub

        Public Sub New()
            MyBase.New("strmid", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim s As String = Nothing
            If ctx.findVariableStr(parameters.s, s) Then
                Dim index As Int64
                If ctx.findVariableInt(parameters.index, index) Then
                    Dim rtn As String = Nothing
                    Dim len As Int64
                    If ctx.findVariableInt(parameters.len, len) Then
                        rtn = strmid(s, index, len)
                    Else
                        rtn = strmid(s, index)
                    End If
                    output = New bare_variable(typeDefination.string, rtn)
                    Return True
                Else
                    raiseError("expect parameter " + parameters.index, errorHandle.errorType.user)
                    Return False
                End If
            Else
                raiseError("expect parameter " + parameters.s, errorHandle.errorType.user)
                Return False
            End If
        End Function
    End Class

    'parameters, s, any, convert to string, input string
    '            sep, any, convert to string, seperators
    '            ignoreEmptyEntity, any, use as bool
    '            value, vector<string> / vector<var>, output
    'return, bool, success or not
    Public Class _strsepar
        Inherits internalFunction

        Private Class cbpara
            Public s As String = Nothing
            Public sep As String = Nothing
            Public ignoreEmptyEntity As Boolean = False

            Public Sub New(ByVal s As String, ByVal sep As String, ByVal ignoreEmptyEntity As Boolean)
                Me.s = s
                Me.sep = sep
                Me.ignoreEmptyEntity = ignoreEmptyEntity
            End Sub
        End Class

        Private Shared Function separate(ByVal s As String, ByVal sep As String, ByVal ignoreEmptyEntity As Boolean, _
                                         ByVal values As vector(Of String)) As Boolean
            strsepar(s, sep, values, ignoreEmptyEntity)
            Return True
        End Function

        Private Shared Function separate(ByVal s As String, ByVal sep As String, ByVal ignoreEmptyEntity As Boolean, _
                                         ByVal values As vector(Of Object)) As Boolean
            Dim vs As vector(Of String) = Nothing
            strsepar(s, sep, vs, ignoreEmptyEntity)
            Dim i As Int64
            Try
                For i = 0 To vs.size() - 1
                    values.push_back(vs(i))
                Next
            Catch
                Return False
            End Try

            Return True
        End Function

        Private Class callback
            Inherits vd_t(Of Boolean)

            Public Overrides Function cb(Of T)(ByRef i As vector(Of T), ByRef rtn As Boolean, _
                                               ByVal ET As typeDefination, _
                                               ByVal ParamArray ps() As Object) As Boolean
                Dim para As cbpara = Nothing
                para = paramarray_get(Of cbpara)(0, ps)
                If ET = typeDefination.string Then
                    rtn = separate(para.s, para.sep, para.ignoreEmptyEntity, convertor.cast(Of vector(Of String))(i))
                    Return True
                ElseIf ET = typeDefination.var Then
                    rtn = separate(para.s, para.sep, para.ignoreEmptyEntity, convertor.cast(Of vector(Of Object))(i))
                    Return True
                Else
                    raiseError("expect parameter " + parameters.value + " is vector<string> / vector<var>.", _
                               errorHandle.errorType.user)
                    Return False
                End If
            End Function
        End Class

        Private Shared cb As callback = Nothing

        Shared Sub New()
            cb = New callback()
            initialMapping(m, parameters.s, parameters.sep, parameters.ignoreEmptyEntity, parameters.value)
        End Sub

        Public Class parameters
            Public Const s As String = "s"
            Public Const sep As String = "sep"
            Public Const ignoreEmptyEntity As String = "ignoreEmptyEntity"
            Public Const value As String = "value"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Public Sub New()
            MyBase.New("strsepar", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim vv As bare_variable = Nothing
            If ctx.findVariable(parameters.value, vv) Then
                If vv.variable().isType(typeDefination.vector) Then
                    Dim rtn As Boolean
                    If vv.invoke(rtn, Nothing, cb, Nothing, Nothing, _
                                 New cbpara(ctx.findVariableStr(parameters.s), _
                                            ctx.findVariableStr(parameters.sep), _
                                            ctx.findVariableBool(parameters.ignoreEmptyEntity))) Then
                        output = New bare_variable(typeDefination.bool, rtn)
                        Return True
                    Else
                        Return False
                    End If
                Else
                    raiseError("expect parameter " + parameters.value + " is vector.", errorHandle.errorType.user)
                    Return False
                End If
            Else
                raiseError("expect parameter " + parameters.value, errorHandle.errorType.user)
                Return False
            End If
        End Function
    End Class

    'parameters, i, any, convert to string, the input
    'return, string, the string to lower
    Public Class _strtolower
        Inherits inputIFunction(Of String, String)

        Public Sub New()
            MyBase.New("tolower")
        End Sub

        Protected Overrides Function invoke(ByVal i As String, ByRef o As String) As Boolean
            o = strtolower(i)
            Return True
        End Function

        Protected Overrides Function enableNoInput() As Boolean
            Return True
        End Function

        Protected Overrides Function finder() As iVariableFinder(Of String)
            Return string_finder()
        End Function

        Protected Overrides Function returnType() As typeDefination
            Return typeDefination.string
        End Function
    End Class

    'parameters, i, any, convert to string, the input
    'return, string, the string to upper
    Public Class _strtoupper
        Inherits inputIFunction(Of String, String)

        Public Sub New()
            MyBase.New("toupper")
        End Sub

        Protected Overrides Function invoke(ByVal i As String, ByRef o As String) As Boolean
            o = strtoupper(i)
            Return True
        End Function

        Protected Overrides Function enableNoInput() As Boolean
            Return True
        End Function

        Protected Overrides Function finder() As iVariableFinder(Of String)
            Return string_finder
        End Function

        Protected Overrides Function returnType() As _types.typeDefination
            Return typeDefination.string
        End Function
    End Class

    Public Class _strlastindexof
        Inherits _strindexof

        Public Sub New()
            MyBase.new("strlastindexof")
        End Sub

        Protected Overrides Function defaultStart(ByVal input As String) As Int64
            Return strlen(input) - 1
        End Function

        Protected Overrides Function index(ByVal input As String, ByVal findstr As String, _
                                           ByVal start As Int64, ByVal indexOfIndex As Int64, _
                                           ByVal carecase As Boolean) As Long
            Return strlastindexof(input, findstr, start, indexOfIndex, carecase)
        End Function
    End Class

    Public Class _strindexof
        Inherits internalFunction

        Public Class parameters
            Public Const input As String = "input"
            Public Const findstr As String = "findstr"
            Public Const carecase As String = "carecase"
            Public Const indexOfIndex As String = "indexOfIndex"
            Public Const start As String = "start"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, _
                           parameters.input, parameters.findstr, _
                           parameters.start, parameters.indexOfIndex, parameters.carecase)
        End Sub

        Public Sub New()
            Me.New("strindexof")
        End Sub

        Protected Sub New(ByVal name As String)
            MyBase.new(name, m)
        End Sub

        Protected Overridable Function index(ByVal input As String, ByVal findstr As String, _
                                             ByVal start As Int64, ByVal indexOfIndex As Int64, _
                                             ByVal carecase As Boolean) As Int64
            Return strindexof(input, findstr, start, indexOfIndex, carecase)
        End Function

        Protected Overridable Function defaultStart(ByVal input As String) As Int64
            Return 0
        End Function

        Protected NotOverridable Overrides Function invoke(ByVal ctx As context, _
                                                           ByRef output As bare_variable) As Boolean
            Dim input As String = Nothing
            Dim findstr As String = Nothing
            input = ctx.findVariableStr(parameters.input)
            findstr = ctx.findVariableStr(parameters.findstr)
            Dim carecase As Boolean = False
            If Not ctx.findVariableBool(parameters.carecase, carecase) Then
                carecase = False
            End If
            Dim indexOfIndex As Int64 = 0
            If Not ctx.findVariableInt(parameters.indexOfIndex, indexOfIndex) Then
                indexOfIndex = 1
            End If
            Dim start As Int64 = 0
            If Not ctx.findVariableInt(parameters.start, start) Then
                start = defaultStart(input)
            End If
            output = New bare_variable(typeDefination.int, index(input, findstr, start, indexOfIndex, carecase))

            Return True
        End Function
    End Class

    Public Class _strrplc
        Inherits internalFunction

        Public Class parameters
            Public Const input As String = "input"
            Public Const [from] As String = "[from]"
            Public Const [to] As String = "to"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            initialMapping(m, parameters.input, parameters.[from], parameters.to)
        End Sub

        Public Sub New()
            MyBase.New("strrplc", m)
        End Sub

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim input As String = Nothing
            Dim [from] As String = Nothing
            Dim [to] As String = Nothing

            input = ctx.findVariableStr(parameters.input)
            [from] = ctx.findVariableStr(parameters.[from])
            [to] = ctx.findVariableStr(parameters.to)

            output = New bare_variable(typeDefination.string, strrplc(input, [from], [to]))
            Return True
        End Function
    End Class

    Public Class stringformat
        Inherits internalFunction

        Public Class parameters
            Public Const i As String = "i"
            Public Const p As String = "p"
        End Class

        Private Shared m As iParametersMapping = Nothing

        Shared Sub New()
            m = mi_ps
            assert_mapping()
        End Sub

        Private Shared Sub assert_mapping()
            assert(strsame(m(0), parameters.i))
            Dim i As Int64
            i = Global.rnd(1, 100)
            assert(strsame(m(i), parameters.p + Convert.ToString(i - 1)))
        End Sub

        Public Sub New()
            MyBase.New("string.format", m)
        End Sub

        Private Shared Function findVariablesCallback(ByVal name As String, _
                                                      ByVal s As String, _
                                                      ByRef v As vector(Of String)) As Boolean
            If isdebugmode() Then
                assert(strstartwith(name, parameters.p))
            End If
            Return v.push_back(s)
        End Function

        Private Shared Function findVariablesCallback(ByVal name As String, _
                                                      ByVal s As String, _
                                                      ByRef obj As Object) As Boolean
            Return findVariablesCallback(name, s, convertor.cast(Of vector(Of String))(obj))
        End Function

        Protected Overrides Function invoke(ByVal ctx As context, ByRef output As bare_variable) As Boolean
            Dim format As String = Nothing
            format = ctx.findVariableStr(parameters.i)
            Dim ps As vector(Of String) = Nothing
            ps = New vector(Of String)()
            ctx.findVariables(AddressOf findVariablesCallback, string_finder(), parameters.p, 0, ps)
            output = New bare_variable(typeDefination.string, String.Format(format, ps.data()))
            Return True
        End Function
    End Class
End Namespace